﻿using System;
using ZoneFiveSoftware.Common.Data.Fitness;
using System.Diagnostics;
using ZoneFiveSoftware.Common.Data.Measurement;
using STCommon.Controller;
using STCommon.Data;
using DistributionPlugin.View;
using ZoneFiveSoftware.Common.Data;

namespace DistributionPlugin.Data
{
    public class DistributionZoneInfo
    {
        public DistributionZoneInfo(INamedLowHighZone namedZone)
        {
            m_NamedZone = namedZone;
        }

        public static DistributionZoneInfo operator +(DistributionZoneInfo distributionZoneInfo, DistributionZoneInfo distributionZoneInfo2)
        {
            if (distributionZoneInfo.m_NamedZone != null &&
                distributionZoneInfo2.m_NamedZone != null &&
                distributionZoneInfo.m_NamedZone != distributionZoneInfo2.m_NamedZone)
            {
                throw new InvalidOperationException("Cannot add zone infos from dfferent INamedLowHighZone");
            }

            DistributionZoneInfo result = new DistributionZoneInfo(distributionZoneInfo.m_NamedZone);

            result.m_TotalDistanceMeters = distributionZoneInfo.m_TotalDistanceMeters + distributionZoneInfo2.m_TotalDistanceMeters;
            result.m_ZoneDistanceMeters = distributionZoneInfo.m_ZoneDistanceMeters + distributionZoneInfo2.m_TotalDistanceMeters;
            result.m_TotalTime = distributionZoneInfo.m_TotalTime + distributionZoneInfo2.m_TotalTime;
            result.m_ZoneTime = distributionZoneInfo.m_ZoneTime + distributionZoneInfo2.m_TotalTime;

            foreach (IValueRange<DateTime> time in distributionZoneInfo.m_Times)
            {
                result.m_Times.Add(time);
            }
            foreach (IValueRange<DateTime> time in distributionZoneInfo2.m_Times)
            {
                result.m_Times.Add(time);
            }

            return result;
        }

        public static DistributionZoneInfo operator +(DistributionZoneInfo distributionZoneInfo, ZoneInfo STZoneInfo)
        {
            if (distributionZoneInfo.m_NamedZone != null &&
                distributionZoneInfo.m_NamedZone != STZoneInfo.Zone)
            {
                throw new InvalidOperationException("Cannot add zone infos from dfferent INamedLowHighZone");
            }

            DistributionZoneInfo result = new DistributionZoneInfo(distributionZoneInfo.m_NamedZone);

            result.m_TotalDistanceMeters = distributionZoneInfo.m_TotalDistanceMeters + STZoneInfo.TotalInfo.TotalDistanceMeters;
            result.m_ZoneDistanceMeters = distributionZoneInfo.m_ZoneDistanceMeters + STZoneInfo.TotalDistanceMeters;
            result.m_TotalTime = distributionZoneInfo.m_TotalTime + STZoneInfo.TotalInfo.TotalTime;
            result.m_ZoneTime = distributionZoneInfo.m_ZoneTime + STZoneInfo.TotalTime;

            foreach (IValueRange<DateTime> time in distributionZoneInfo.m_Times)
            {
                result.m_Times.Add(time);
            }
            foreach (IValueRange<DateTime> time in STZoneInfo.Times)
            {
                result.m_Times.Add(time);
            }

            return result;
        }

        public INamedLowHighZone NamedZone
        {
            get { return m_NamedZone; }
        }

        public String GetRangeStartLabel(ILabelUnitProvider labelUnitProvider)
        {
            if (NamedZone == null)
            {
                throw new InvalidOperationException("Cannot get the range label of a generic zone nfo");
            }

            return GetRangeLabel(labelUnitProvider, NamedZone.Low);
        }

        public String GetRangeEndLabel(ILabelUnitProvider labelUnitProvider)
        {
            if (NamedZone == null)
            {
                throw new InvalidOperationException("Cannot get the range label of a generic zone nfo");
            }

            return GetRangeLabel(labelUnitProvider, NamedZone.High);
        }

        private String GetRangeLabel(ILabelUnitProvider labelUnitProvider, float value)
        {
            if (labelUnitProvider != null &&
                labelUnitProvider.DataType == Enums.SportTracksDataTrackTypes.Speed &&
                labelUnitProvider.SpeedUnit == Speed.Units.Pace)
            {
                return Utils.TimeMinutesToString(value);
            }
            else
            {
                return String.Format("{0:0.##}", value);
            }
        }
        public String GetRangeLabel(ILabelUnitProvider labelUnitProvider)
        {
            return String.Format("[{0}, {1}[", GetRangeStartLabel(labelUnitProvider), GetRangeEndLabel(labelUnitProvider));
        }

        public double TimePercent
        {
            get
            {
                if (m_TotalTime.TotalMilliseconds > 0)
                {
                    return m_ZoneTime.TotalMilliseconds / m_TotalTime.TotalMilliseconds;
                }

                return 0;
            }
        }

        public double DistancePercent
        {
            get
            {
                if (m_TotalDistanceMeters > 0)
                {
                    return m_ZoneDistanceMeters / m_TotalDistanceMeters;
                }

                return 0;
            }
        }

        public TimeSpan ZoneTime
        {
            get { return m_ZoneTime; }
        }

        public double ZoneDistanceMeters
        {
            get { return m_ZoneDistanceMeters; }
        }

        public ValueRangeSeries<DateTime> Times
        {
            get { return m_Times; }
        }

        private INamedLowHighZone m_NamedZone = null;
        private TimeSpan m_TotalTime = new TimeSpan(0);
        private TimeSpan m_ZoneTime = new TimeSpan(0);
        private double m_TotalDistanceMeters = 0;
        private double m_ZoneDistanceMeters = 0;
        private ValueRangeSeries<DateTime> m_Times = new ValueRangeSeries<DateTime>();
    }
}
